package cn.t.repository.impl.order;


import cn.t.converter.order.OrderConverter;
import cn.t.core.mode.YesNoEnum;
import cn.t.core.repoistory.RepositoryImpl;
import cn.t.dto.order.OrderQueryRequest;
import cn.t.dto.order.QuotationQueryRequest;
import cn.t.enums.OptionTypeEnum;
import cn.t.enums.order.ErrorTypeEnum;
import cn.t.enums.order.MsvmOrderStatusEnum;
import cn.t.enums.order.OrderTransferStatusEnum;
import cn.t.enums.order.OrderTypeEnum;
import cn.t.model.order.OrderDO;
import cn.t.persistence.entity.order.OrderPO;
import cn.t.persistence.mapper.order.OrderMapper;
import cn.t.repository.order.OrderRepository;
import cn.t.utils.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 领料订单表(Order)数据仓库
 *
 * @author t
 * @since 2024-05-24 10:18:09
 */
@Slf4j
@Repository
@AllArgsConstructor
public class OrderRepositoryImpl extends RepositoryImpl<OrderMapper, OrderPO, OrderConverter, OrderDO> implements OrderRepository {


    @Override
    public List<OrderDO> findByModel(OrderDO orderDO, int start, Integer pageSize, String field, String direction) {

        String lastSql = getLastSql(start, pageSize, field, direction);

        List<OrderPO> list = getWrapper(orderDO)
                .last(lastSql)
                .list();
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }

        return list.stream().map(converter::po2Model).collect(Collectors.toList());
    }

    private static String getLastSql(int start, Integer pageSize, String field, String direction) {
        return StringUtils.hasText(field) ?
                " order by " + field + " " + direction + " limit " + start + "," + pageSize
                :
                " limit " + start + "," + pageSize;
    }

    private LambdaQueryChainWrapper<OrderPO> getWrapper(OrderDO orderDO) {
        LambdaQueryChainWrapper<OrderPO> wrapper = lambdaQuery();
        if (!ObjectUtils.isEmpty((orderDO.getOrderSn()))) {
            wrapper.eq(OrderPO::getOrderSn, orderDO.getOrderSn());
        }
        if (!ObjectUtils.isEmpty((orderDO.getOrderSnList()))) {
            wrapper.in(OrderPO::getOrderSn, orderDO.getOrderSnList());
        }
        if (!ObjectUtils.isEmpty((orderDO.getUserId()))) {
            wrapper.eq(OrderPO::getUserId, orderDO.getUserId());
        }
        if (!ObjectUtils.isEmpty((orderDO.getParticipantId()))) {
            wrapper.eq(OrderPO::getParticipantId, orderDO.getParticipantId());
        }
        if (!ObjectUtils.isEmpty((orderDO.getFirmId()))) {
            wrapper.eq(OrderPO::getFirmId, orderDO.getFirmId());
        }
        if (!ObjectUtils.isEmpty((orderDO.getDeviceId()))) {
            wrapper.eq(OrderPO::getDeviceId, orderDO.getDeviceId());
        }
        if (!ObjectUtils.isEmpty((orderDO.getOrderStatus()))) {
            wrapper.eq(OrderPO::getOrderStatus, orderDO.getOrderStatus());
        }
        if (!ObjectUtils.isEmpty((orderDO.getGmtSync()))) {
            wrapper.eq(OrderPO::getGmtSync, orderDO.getGmtSync());
        }
        if (!ObjectUtils.isEmpty((orderDO.getSyncStatus()))) {
            wrapper.eq(OrderPO::getSyncStatus, orderDO.getSyncStatus());
        }
        if (!ObjectUtils.isEmpty((orderDO.getSyncResult()))) {
            wrapper.eq(OrderPO::getSyncResult, orderDO.getSyncResult());
        }
        if (!ObjectUtils.isEmpty((orderDO.getOrderTransferStatus()))) {
            wrapper.eq(OrderPO::getOrderTransferStatus, orderDO.getOrderTransferStatus());
        }
        if (!ObjectUtils.isEmpty((orderDO.getGmtTransfer()))) {
            wrapper.eq(OrderPO::getGmtTransfer, orderDO.getGmtTransfer());
        }
        if (!ObjectUtils.isEmpty((orderDO.getTransferUserId()))) {
            wrapper.eq(OrderPO::getTransferUserId, orderDO.getTransferUserId());
        }
        if (!ObjectUtils.isEmpty((orderDO.getTransferParticipantId()))) {
            wrapper.eq(OrderPO::getTransferParticipantId, orderDO.getTransferParticipantId());
        }
        if (!ObjectUtils.isEmpty((orderDO.getTransferFirmId()))) {
            wrapper.eq(OrderPO::getTransferFirmId, orderDO.getTransferFirmId());
        }
        if (!ObjectUtils.isEmpty((orderDO.getGmtPush()))) {
            wrapper.eq(OrderPO::getGmtPush, orderDO.getGmtPush());
        }
        if (!ObjectUtils.isEmpty((orderDO.getPushStatus()))) {
            wrapper.eq(OrderPO::getPushStatus, orderDO.getPushStatus());
        }
        if (!ObjectUtils.isEmpty((orderDO.getCostCenterId()))) {
            wrapper.eq(OrderPO::getCostCenterId, orderDO.getCostCenterId());
        }
        if (!ObjectUtils.isEmpty((orderDO.getGmtModified()))) {
            wrapper.between(OrderPO::getGmtModified, orderDO.getGmtModifiedStart(), orderDO.getGmtModifiedEnd());
        }
        if (!ObjectUtils.isEmpty((orderDO.getGmtClose()))) {
            wrapper.ge(OrderPO::getGmtClose, orderDO.getGmtClose());
        }

        if (!ObjectUtils.isEmpty((orderDO.getGmtCreated()))) {
            wrapper.between(OrderPO::getGmtCreated, orderDO.getGmtCreatedStart(), orderDO.getGmtCreatedEnd());
        }
        return wrapper;
    }

    public LambdaQueryChainWrapper<OrderPO> getQueryWrapper(OrderQueryRequest orderQueryDO) {

        LambdaQueryChainWrapper<OrderPO> wrapper = lambdaQuery();
        addConditionIfNotEmpty(wrapper, OrderPO::getOrderSn, orderQueryDO.getOrderSn());
        wrapper.eq(ObjectUtils.isNotEmpty(orderQueryDO.getFirmId()), OrderPO::getFirmId, orderQueryDO.getFirmId());

        addConditionIfNotEmpty(wrapper, OrderPO::getWorkOrderSn, orderQueryDO.getWorkOrderSn());

        addConditionIfNotEmpty(wrapper, OrderPO::getUserName, orderQueryDO.getUserName());
        addConditionIfNotEmpty(wrapper, OrderPO::getCardCode, orderQueryDO.getCardCode());
        addConditionIfNotEmpty(wrapper, OrderPO::getCostCenterId, orderQueryDO.getCostCenterId());

        wrapper.eq(ObjectUtils.isNotEmpty(orderQueryDO.getDeviceId()), OrderPO::getDeviceId, orderQueryDO.getDeviceId());
        wrapper.in(ObjectUtils.isNotEmpty(orderQueryDO.getDeviceIs()), OrderPO::getDeviceId, orderQueryDO.getDeviceIs());
        wrapper.eq(orderQueryDO.getOrderTransferStatus() != null, OrderPO::getOrderTransferStatus, orderQueryDO.getOrderTransferStatus());
        wrapper.in(ObjectUtils.isNotEmpty(orderQueryDO.getUserIds()), OrderPO::getUserId, orderQueryDO.getUserIds());
        wrapper.in(ObjectUtils.isNotEmpty(orderQueryDO.getWorkOrderSns()), OrderPO::getWorkOrderSn, orderQueryDO.getWorkOrderSns());
        if (!ObjectUtils.isEmpty(orderQueryDO.getGmtStart())) {
            wrapper.ge(OrderPO::getGmtCreated, DateUtil.startDate(orderQueryDO.getGmtStart()));
        }
        if (!ObjectUtils.isEmpty(orderQueryDO.getDeviceName())) {
            wrapper.like(OrderPO::getDeviceName, orderQueryDO.getDeviceName());
        }
        if (!ObjectUtils.isEmpty(orderQueryDO.getGmtEnd())) {
            wrapper.le(OrderPO::getGmtCreated, DateUtil.endDate(orderQueryDO.getGmtEnd()));
        }
        if (ObjectUtils.isNotEmpty(orderQueryDO.getSkuCode())) {
            wrapper.inSql(OrderPO::getOrderSn, "SELECT order_sn FROM t_order_detail WHERE sku_code LIKE '%" + orderQueryDO.getSkuCode() + "%'");

        }
        if (ObjectUtils.isNotEmpty(orderQueryDO.getSkuName())) {
            wrapper.inSql(OrderPO::getOrderSn, "SELECT order_sn FROM t_order_detail WHERE sku_name LIKE '%" + orderQueryDO.getSkuName() + "%'");
        }
        if (ObjectUtils.isNotEmpty(orderQueryDO.getExceptionType())) {
            wrapper.inSql(OrderPO::getOrderSn, "SELECT order_sn FROM t_exception_log WHERE exception_type = " + orderQueryDO.getExceptionType());
        }

        if (ObjectUtils.isNotEmpty(orderQueryDO.getOrderStatusEnum())) {
            wrapper.in(OrderPO::getOrderStatus, orderQueryDO.getOrderStatusEnum());
            boolean b = new HashSet<>(MsvmOrderStatusEnum.NORMALCODES).containsAll(orderQueryDO.getOrderStatusEnum());
            if (b) {
                wrapper.ne(OrderPO::getOrderTransferStatus, OrderTransferStatusEnum.PROCESSED);
            }
        }
        boolean b = new HashSet<>(MsvmOrderStatusEnum.NORMALCODES).containsAll(orderQueryDO.getOrderStatusEnum());
        return wrapper;
    }

    private void addConditionIfNotEmpty(LambdaQueryChainWrapper<OrderPO> wrapper, SFunction<OrderPO, ?> property, Object value) {
        Optional.ofNullable(value)
                .filter(v -> v.toString().trim().length() > 0)
                .ifPresent(val -> wrapper.eq(property, val.toString().trim()));
    }

    @Override
    public long count(OrderDO orderDO) {
        return getWrapper(orderDO).count();
    }

    @Override
    public Boolean removeOrderById(Long orderId) {
        LambdaUpdateChainWrapper<OrderPO> wrapper = lambdaUpdate();
        wrapper.eq(OrderPO::getId, orderId);
        wrapper.set(OrderPO::getIsDeleted, YesNoEnum.TRUE);
        return wrapper.update();
    }

    @Override
    public OrderDO findInfoByModel(OrderDO dataDo) {
        OrderPO order = baseMapper.selectOne(getWrapper(dataDo).getWrapper());
        if (ObjectUtils.isEmpty((order))) {
            return null;
        }
        return converter.po2Model(order);
    }

    @Override
    public List<OrderDO> queryOrderList(OrderQueryRequest orderQueryDO, int start, Integer pageSize, String field, String direction) {
        String lastSql = getLastSql(start, pageSize, field, direction);
        List<OrderPO> list = getQueryWrapper(orderQueryDO).exists(" SELECT 1    FROM t_order_detail   WHERE t_order_detail.order_sn = t_order.order_sn")
                .last(lastSql).list();
        return converter.po2doList(list);
    }

    @Override
    public List<OrderDO> queryErrOrderList(OrderQueryRequest orderQueryDO, int start, Integer pageSize, String field, String direction) {
        String lastSql = getLastSql(start, pageSize, field, direction);
        LambdaQueryChainWrapper<OrderPO> queryWrapper = getErrWrapper(orderQueryDO);
        List<OrderPO> list = queryWrapper.last(lastSql).list();
        return converter.po2doList(list);
    }


    public Long queryErrOrderCount(OrderQueryRequest orderQueryDO) {
        return getErrWrapper(orderQueryDO).count();
    }

    private LambdaQueryChainWrapper<OrderPO> getErrWrapper(OrderQueryRequest orderQueryDO) {
        orderQueryDO.setOrderStatusEnum(MsvmOrderStatusEnum.ERRCODES);
        LambdaQueryChainWrapper<OrderPO> queryWrapper = getQueryWrapper(orderQueryDO);
        // 疑似未领取查询
        if (ErrorTypeEnum.ERROR10.getCode().equals(orderQueryDO.getExceptionType())) {
            return queryWrapper;
        } else if (orderQueryDO.getAll()) {
            return queryWrapper;
        } else {
            //异常列表查询（排除疑似未领取）
            queryWrapper.inSql(OrderPO::getOrderSn, "SELECT order_sn FROM t_exception_log WHERE exception_type != " + ErrorTypeEnum.ERROR10.getCode() + " and business_type != " + OptionTypeEnum.rs_open.getCode());
        }
        return queryWrapper;
    }

    public LambdaUpdateChainWrapper<OrderPO> updateWrapper(OrderDO orderDO) {
        return lambdaUpdate()
                .in(OrderPO::getOrderSn, orderDO.getOrderSns())
                .set(OrderPO::getSyncStatus, orderDO.getSyncStatus());
    }

    @Override
    public Long queryOrderCount(OrderQueryRequest orderQueryDO, OrderTypeEnum orderType) {
        if (ObjectUtils.isEmpty(orderQueryDO.getOrderStatusEnum())) {
            orderQueryDO.setOrderStatusEnum(MsvmOrderStatusEnum.NORMALCODES);
        }
        return getQueryWrapper(orderQueryDO).exists(" SELECT 1    FROM t_order_detail   WHERE t_order_detail.order_sn = t_order.order_sn").count();
    }

    @Override
    public List<OrderDO> orderQuoteOrders(QuotationQueryRequest orderQueryDO) {
        orderQueryDO.setOrderStatusEnum(MsvmOrderStatusEnum.NORMALCODES);
        LambdaQueryChainWrapper<OrderPO> queryWrapper = getQueryWrapper(orderQueryDO);
        queryWrapper.notIn(ObjectUtils.isNotEmpty(orderQueryDO.getNoOrderSnList()), OrderPO::getOrderSn, orderQueryDO.getNoOrderSnList());
        queryWrapper.in(ObjectUtils.isNotEmpty(orderQueryDO.getOrderSnList()), OrderPO::getOrderSn, orderQueryDO.getOrderSnList());
        List<OrderPO> list = queryWrapper.list();
        return converter.po2doList(list);
    }

    public void updateOrder(OrderDO orderDO) {
        updateWrapper(orderDO).update();
    }
}
